package algeff

type Handler[R any] struct {
	inner func(any, Ctx, Cont[any, any]) (any, bool)
}

type Handlers[R1, R2 any] struct {
	returns  func(Ctx, R1) R2
	handlers []Handler[R2]
}

type Cont[R, O any] func(O) R

func Ctl[R, O any, E Effect[O]](h func(E, Ctx, Cont[R, O]) R) Handler[R] {
	return Handler[R]{func(eAny any, ctx Ctx, cont Cont[any, any]) (any, bool) {
		e, ok := eAny.(E)
		if !ok {
			return nil, false
		}
		return h(e, ctx, func(o O) R { return cont(o).(R) }), false
	}}
}

func Fun[R, O any, E Effect[O]](h func(E, Ctx) O) Handler[R] {
	return Handler[R]{func(eAny any, ctx Ctx, _ Cont[any, any]) (any, bool) {
		e, ok := eAny.(E)
		if !ok {
			return nil, false
		}
		return h(e, ctx), true
	}}
}

func Dyn[R, O any, E Effect[O]](h func(E, Ctx, Cont[R, O]) (R, O, bool)) Handler[R] {
	return Handler[R]{func(eAny any, ctx Ctx, cont Cont[any, any]) (any, bool) {
		e, ok := eAny.(E)
		if !ok {
			return nil, false
		}
		r, o, c := h(e, ctx, func(o O) R { return cont(o).(R) })
		if c {
			return o, true
		}
		return r, false
	}}
}

func NewHandlers[R any](h ...Handler[R]) Handlers[R, R] {
	r := func(_ Ctx, r R) R { return r }
	return Handlers[R, R]{returns: r, handlers: h}
}

func NewHandlersReturns[R1, R2 any](r func(Ctx, R1) R2, h ...Handler[R2]) Handlers[R1, R2] {
	return Handlers[R1, R2]{returns: r, handlers: h}
}
